Repository navigation
fix(bin): stop false wedge alarms for deliberately stood-down workers - #3281
AgardnerAU wants to merge 51 commits into
Conversation
|
|
Speaking as Kun's firstmate: Reviewed HEAD Contract-class: new-default. Unconfigured fleet now has first-class VISION (per rule):
Attestation HTML binds |
…pair and rollback
…e before wiring retire
… refuse an absent CLI
…ed run projections
d402739 to
562d760
Compare
|
Speaking as Kun's firstmate: re-triage after newer author activity (HEAD moved since 2026-08-29 stamp). Outcome: waiting-ci (attestation now MATCH; first-time fork CI re-approved this pass for new HEAD and is pending) contract-class: new-default — unconfigured fleet gains first-class VISION.md
Attestation: MATCH |
|
CI run 35379109555, job 105717538312, failed on one assertion: I could not reproduce it on either side. Against this branch head On the mechanism: One thing you should weigh yourselves: this branch adds about 100 lines of tests to Would you be willing to re-run that job? A re-run is the cheapest way to tell a timing-dependent failure from a real regression. |
|
Follow-up to my previous comment: I can now reproduce that failure deterministically, which turns the earlier "could not reproduce" into a causal explanation. The fixture A missing file rather than wrong contents, and the same assertion text. That is a pre-existing race in the fixture, independent of this change. To be straight about what does not support that conclusion: I also ran the suite at 24-way concurrency, and all 24 runs failed — but on different assertions ( Could you re-run job 105717538312? I cannot do it myself — Everything else is green: 18 of 19 checks, including the body-compliance run. |
|
Speaking as Kun's firstmate: re-triage after newer author activity (HEAD still HEAD Attestation: MATCH. CI run Contract-class: new-default (prior class stands). Unconfigured fleet gains first-class VISION.md (per rule)
Outcome: waiting-author (CI red; author owns the contributions budget-hang fix). Firstmate flag: no — not otherwise ready while CI-red. Security FYI: none (fail-closed; live agents stay in wedge detection). |
…r-false-wedge-alarms
…r-false-wedge-alarms # Conflicts: # bin/fm-control.sh # docs/agent-control.md # docs/scripts.md
test_budget_exhaustion_keeps_prior_record's `hang` mode faulted the first forge call of the observation, so the one line proving the observation had started was written by the very process the budget deadline was about to kill. With a one-second budget, a contended runner could spend the whole bound spawning the fixture, leaving $FORGE/calls absent and failing "budget exhaustion (hang) never started the observation". Move the hang onto a later call so the calls that prove the observation started are ordinary completed reads, and raise the budget to five seconds, which is still `-le 5` and so still classifies a killed read as budget exhaustion rather than an unavailable forge. The assertions are unchanged. Record preservation remains the proof that exhaustion actually happened, so the case cannot pass vacuously: disabling the hang fault still fails the test.
|
Rebased onto current Three conflicts, additive on both sides: One change outside the original scope, flagged because it is a reviewer-visible claim rather than a merge decision. CI failed at "budget exhaustion (hang) never started the observation" in The hang now targets a later call, so that evidence comes from completed reads rather than the read being killed, and the budget is five seconds - still I believe the pattern is wider and have left the rest alone: the |
|
Updated with current upstream main. The PR is mergeable and ready for CI once the fork workflow runs are approved. |
|
Refreshed onto current upstream main at 9c15ae1; the two conflicts (operational-home-layout state list, teardown rm list) were additive and both sides are kept. The budget-hang fixture fix from the earlier refresh is carried unchanged (upstream main has not changed that test); tests/fm-contributions.test.sh passed 3/3 runs idle and 5/5 under heavy CPU load locally. Mergeable and ready for CI - the CI and Require no-mistakes runs are awaiting workflow approval. |
…r-false-wedge-alarms # Conflicts: # bin/fm-control.sh # tests/fm-contributions.test.sh
|
Merged current upstream main into this branch (head 9dc61a0), resolving the conflicts in bin/fm-control.sh and tests/fm-contributions.test.sh; the budget-hang fixture fix is kept. The branch is up to date with main and ready for CI; the workflow runs are waiting for maintainer approval. |
|
Speaking as Kun's firstmate (OSS triage, not the captain). Thanks @AgardnerAU. My 09-19 stamp was waiting-author, because CI was red on the contributions budget-hang test at I re-reviewed the tip diff. There are no workflow or secret changes, so I approved the fork runs: CI Contract-class: new-default (unchanged). An unconfigured fleet gains first-class VISION (unchanged):
Outcome: waiting-ci. The author-side blocker is cleared. Once CI and no-mistakes are green, this goes to the captain to merge or leave. It won't auto-merge. Nothing is needed from you right now. |
…r-false-wedge-alarms # Conflicts: # tests/fm-crew-state.test.sh
|
Merged current upstream main into this branch (head 876c626); the one test-file conflict is resolved and the branch has no conflicts with main. The affected tests pass locally. Ready for CI - the fork workflow runs are waiting for maintainer approval. |
|
Speaking as Kun's firstmate: thanks @AgardnerAU — tip Contract-class: new-default (unchanged). Unconfigured fleet still gains first-class stand-down verbs, durable VISION: one-interface / scripts / restart / spine / vendor / scope align; authority in tension (no opt-in gate) — hence new-default. Outcome: waiting-ci. Main is red; no merge. When CI + no-mistakes are green on a green main, this goes to the captain to merge or leave (not auto-merge). Live 8/10 noted (relaunch + in-flight NM covered by suites). Nothing needed from you right now. |
Intent
On 2026-10-13 the captain approved updating 11 open upstream PRs, including #3281 ("yes, update those 11 PR's"). The approved update: merge current upstream main into each PR, fix the conflicts, run the tests, look into red checks, push, and post a short note on each PR.
Context: A read-only check on 2026-10-13 found this PR CONFLICTING with current upstream main (head
9dc61a0d). Upstream kunchenguid/firstmate closes a PR after 14 days of AUTHOR silence; only a push or comment by the author resets that clock, and a stale close is irreversible. On 2026-09-18 the captain asked for every PR waiting on us in the kunchenguid repositories to be kept alive.The PR is on branch
fm/fm-stooddown-worker-false-wedge-alarmsfrom the forkAgardnerAU/firstmateintokunchenguid:main. Reuse that branch and that PR; never replace them.PR #3281 is "fix(bin): stop false wedge alarms for deliberately stood-down workers": a worker that firstmate deliberately stood down (no agent running, work preserved for a later relaunch) must not raise false wedge or stuck alarms, while genuine failures and vanished endpoints stay visible.
What Changed
fm-controlverbs,stand-downandrepair-worker-state, for tmux only. They use a newbin/fm-worker-state-lib.shand an exactstate/<id>.worker-staterecord.stand-downstops the agent for a held ship or scout task. It publishes the record only after the classifier proves the agent is gone. It refuses when the task has an in-flight no-mistakes run, when that check cannot be answered (the new branch-run verdict inbin/fm-nm-run-lib.sh), when a steering instruction is still waiting in the inbox, or when an already-dead agent has nopaused:/captain-held:declaration.repair-worker-statechanges the record only toward supervision: it clears a record that cannot be proven or that a live agent contradicts. It never creates a hold.fm-watchskips pane-stale and wedge detection for a window only when the record saysstood-downand the endpoint is still proven dead, so a live worker behind a stale record is still checked.fm-crew-statereports a proven hold asparked · source: worker-state. A live run still takes priority over the hold, and a vanished endpoint reportsunknown.fm-sendrefuses input to a proven stood-down task, andfm-teardownremoves the record.fm-spawn --relaunchclears the record before it starts the replacement and restores it if the relaunch aborts. The control docs, architecture docs, configuration docs and script docs describe the new verbs. New tests cover the stand-down lifecycle and its refusals, relaunch from a stood-down worker, crew-state reporting, send refusal and the watcher exemption.🤖 Generated with Claude Code
Risk Assessment
✅ Low: The only change since the earlier review rounds is a clean merge of upstream main: the one conflict (tests/fm-crew-state.test.sh) keeps both the branch's stood-down tests and main's Forgejo test and calls all of them. In bin/fm-spawn.sh, the worker-state restore on an aborted relaunch and main's secondmate busy-arm rework now sit together correctly.
Testing
All six targeted suites (fm-control, fm-crew-state, fm-control-relaunch, fm-send-inbox, fm-task-inbox and fm-watch-triage) finished with exit 0 and no failures. I then built a disposable lab home with a private tmux socket and a real Claude CLI worker. I drove the real fm-control, fm-crew-state, fm-send, fm-watch and fm-wake-drain scripts through eight live scenarios, and all eight passed. Two more scenarios were not driven live, so they are marked untested: relaunch from a stood-down task, and stand-down refusal while a no-mistakes run is in flight. The suites cover both. I stopped the lab tmux server and the orphaned lab watcher, and removed the lab's socket directory. The permission layer refused
rm -rfon the lab home in$TMPDIR(/var/folders/.../T/fm-lab.J5cQV9), so that directory is still there. There is no UI surface, so the evidence is CLI transcripts and a pane capture.Evidence: Live stand-down transcript (S1-S9)
Source: Live stand-down transcript (S1-S9)
Evidence: Live real watcher cycles (t1 never hashed or alarmed; t2 surfaced as stale)
Source: Live real watcher cycles (t1 never hashed or alarmed; t2 surfaced as stale)
Evidence: Live Claude pane after fm-send to a live worker behind an old record
Source: Live Claude pane after fm-send to a live worker behind an old record
Evidence: fm-control suite log
Source: fm-control suite log
Evidence: fm-crew-state suite log
Source: fm-crew-state suite log
Evidence: Key live output
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
⏭️ **Rebase** - skipped
AGENTS.md- merge conflict rebasing onto origin/mainbin/fm-control.sh- merge conflict rebasing onto origin/mainbin/fm-teardown.sh- merge conflict rebasing onto origin/maindocs/agent-control.md- merge conflict rebasing onto origin/maindocs/architecture.md- merge conflict rebasing onto origin/maindocs/configuration.md- merge conflict rebasing onto origin/maintests/fm-control-relaunch.test.sh- merge conflict rebasing onto origin/maintests/fm-crew-state.test.sh- merge conflict rebasing onto origin/main✅ **Review** - passed
✅ No issues found.
✅ **Test** - passed
✅ No issues found.
bash tests/fm-control.test.sh(exit 0)bash tests/fm-crew-state.test.sh(exit 0)bash tests/fm-control-relaunch.test.sh(exit 0)bash tests/fm-send-inbox.test.sh(exit 0)bash tests/fm-task-inbox.test.sh(exit 0)bash tests/fm-watch-triage.test.sh(exit 0, including both stood-down watcher tests)Live lab:bin/fm-lab-home.sh createplus a privatetmux -L fm-labsocket, with realclaude2.1.296 in pane fm-t1 and a plain shell in fm-t2Live:bin/fm-control.sh t1 stand-down, run once and then againLive:bin/fm-crew-state.sh t1/t2before and afterLive:bin/fm-send.sh t1 helloagainst the stood-down taskLive:bin/fm-control.sh t2 stand-downwith no declared hold, then again after apaused:lineLive: 4 cycles of realbin/fm-watch.shwithbin/fm-wake-drain.shacknowledgementsLive:bin/fm-control.sh t1 repair-worker-statewith the endpoint dead, then afterkill-windowLive: manualclauderelaunch in fm-t2 behind a stood-down record, thenfm-crew-state,fm-sendandrepair-worker-state✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.